package com.zzgele.qmzb.api.web;

import com.alibaba.alipay.AlipayConfig;
import com.alibaba.alipay.AlipayCore;
import com.alibaba.alipay.AlipayNotify;
import com.alibaba.alipay.RSA;
import com.alibaba.boot.dubbo.annotation.DubboConsumer;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.zzgele.qmzb.api.core.Constants;
import com.zzgele.qmzb.api.core.Result;
import com.zzgele.qmzb.api.core.ResultGenerator;
import com.zzgele.qmzb.api.model.DiamondLog;
import com.zzgele.qmzb.api.model.DiamondRechargeLog;
import com.zzgele.qmzb.api.model.User;
import com.zzgele.qmzb.api.service.DiamondLogService;
import com.zzgele.qmzb.api.service.DiamondRechargeLogService;
import com.zzgele.qmzb.api.service.UserService;
import com.zzgele.qmzb.api.utils.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tk.mybatis.mapper.entity.Condition;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by Martin on 2017/07/09.
 */
@RestController
@RequestMapping("/pay")
public class PayController {
    private final Logger logger = LoggerFactory.getLogger(PayController.class);
    @DubboConsumer
    private DiamondRechargeLogService diamondRechargeLogService;
    @DubboConsumer
    private DiamondLogService diamondLogService;
    @DubboConsumer
    private UserService userService;

    @PostMapping("/iap_verify")
    public Result iap_verify(Long login_uid, String receipt, String transaction_id, Integer version) {
        if(StringUtil.isEmpty(receipt)){
            return ResultGenerator.genFailResult("参数receipt异常");
        }
        if(version == null){
            return ResultGenerator.genFailResult("参数version异常");
        }

        //TODO:增加重复提交的验证【Redis】

        Integer payType = version > Constants.IOS_APP_STORE_VERSION ? Constants.PAY_TYPE_IAP_SANDBOX : Constants.PAY_TYPE_IAP;

        //开始验证
        String url = version > Constants.IOS_APP_STORE_VERSION ? Constants.IAP_CERTIFICATE_URL_TEST : Constants.IAP_CERTIFICATE_URL;
        final String certificateCode = receipt;
        if(StringUtils.isNotEmpty(certificateCode)){
            String result = IapUtil.sendHttpsCoon(url, certificateCode);
            if(result == null) {
                logger.warn("请求苹果验证服务器超时, login_uid:{}, receipt:{}, transaction_id:{}, version:{}", login_uid, receipt, transaction_id, version);
                return ResultGenerator.genFailResult("请求苹果验证服务器超时");
            }
            /**
             * 服务器二次验证代码
             * 21000 App Store不能读取你提供的JSON对象
             * 21002 receipt-data域的数据有问题
             * 21003 receipt无法通过验证
             * 21004 提供的shared secret不匹配你账号中的shared secret
             * 21005 receipt服务器当前不可用
             * 21006 receipt合法，但是订阅已过期。服务器接收到这个状态码时，receipt数据仍然会解码并一起发送
             * 21007 receipt是Sandbox receipt，但却发送至生产系统的验证服务
             * 21008 receipt是生产receipt，但却发送至Sandbox环境的验证服务
             */
            logger.info("iap verify result : {}", result);

            try {
                JSONObject jsonObject = JSONObject.parseObject(result);
                String environmentString = jsonObject.getString("environment"); //Sandbox
                Integer status = jsonObject.getIntValue("status");
                logger.debug("pay->status{}",status.toString());
                logger.debug(JSON.toJSONString(jsonObject));
                if(status.equals(0)) {
                    JSONObject jsonObjectReceipt = jsonObject.getJSONObject("receipt");
                    String bundleId = jsonObjectReceipt.getString("bundle_id");
                    Integer applicationVersion = jsonObjectReceipt.getIntValue("application_version");
                    if(bundleId.equals(Constants.IOS_BUNDLE_ID) && applicationVersion.equals(version) ) {
                        //application_version =1
                        JSONArray jsonArrayInApp = jsonObjectReceipt.getJSONArray("in_app");
                        JSONObject jsonObjectInApp = jsonArrayInApp.getJSONObject(0);

                        //"purchase_date": "2017-08-08 08:52:50 Etc/GMT"
                        Date datePurchaseDate = jsonObjectInApp.getDate("original_purchase_date");
                        Integer createTime = DateUtil.getUnixTimeStampByDate(datePurchaseDate);
                        //System.out.println(createTime);

                        //"product_id": "com.42"
                        String productId = jsonObjectInApp.getString("product_id");
                        BigDecimal money = IapUtil.getIpaMoney(productId);

                        //"transaction_id": "1000000322503780"
                        String transactionId = jsonObjectInApp.getString("transaction_id");

                        if(!money.equals(new BigDecimal(0)) && transactionId.equals(transaction_id)) {
                            String productIdReal = productId.replace("com.", "");
                            BigDecimal diamond = new BigDecimal(productIdReal);

                            logger.info("iap_pay===>diamond:{} money:{} create_time:{} transaction_id:{}", diamond, money, createTime, transactionId);
                            String payResult = doPay(login_uid, payType, transactionId, money, diamond, createTime, result);
                            if (payResult == null) {
                                return ResultGenerator.genSuccessResult();
                            } else {
                                return ResultGenerator.genFailResult(payResult);
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                logger.warn("iap支付异常：{}", ex.toString());
                return ResultGenerator.genFailResult("支付异常，请联系客服!");
            }
        }
        return ResultGenerator.genFailResult("验证失败");
    }

    private String doPay(Long login_uid, Integer type, String transactionId, BigDecimal money, BigDecimal diamond, Integer create_time, String result) {
        //检测充值日志
        Condition condition = new Condition(DiamondLog.class);
        condition.createCriteria().andCondition("type=" + type + " AND transaction_id=" + transactionId + " AND status=" + Constants.PAY_STATUS_PAYED);
        List<DiamondRechargeLog> diamondRechargeLogList = diamondRechargeLogService.findByCondition(condition);
        if(diamondRechargeLogList.size() != 0) {
            logger.warn("重复提交充值, 用户ID：{}, type:{}, 第三方订单ID:{}", login_uid, type, transactionId);
            return "重复提交充值";
        }

        //记录充值日志
        DiamondRechargeLog diamondRechargeLog = new DiamondRechargeLog();
        diamondRechargeLog.setContent(result);
        diamondRechargeLog.setCreateTime(create_time);
        diamondRechargeLog.setDiamond(diamond);
        diamondRechargeLog.setMoney(money);
        diamondRechargeLog.setTransactionId(transactionId);
        diamondRechargeLog.setType(type);
        diamondRechargeLog.setStatus(Constants.PAY_STATUS_PAYED);
        diamondRechargeLog.setUid(login_uid);
        diamondRechargeLog.setUpdateTime(DateUtil.getCurUnixTimeStampInt());
        diamondRechargeLogService.save(diamondRechargeLog);

        Long diamondRechargeLogId = diamondRechargeLog.getId();
        logger.info("diamondRechargeLogId: {}", diamondRechargeLogId);

        //获取用户的余额
        User user = userService.findById(login_uid);
        if(user == null) {
            logger.warn("用户(ID{})未找到, 充值记录ID:{}", login_uid, diamondRechargeLogId);
            return "充值用户不存在";
        }
        //用户当前余额
        BigDecimal diamondBalance = user.getDiamond();
        diamondBalance = CalculateUtil.getAddBalance(diamondBalance, diamond);

        //记录用户钻记录
        DiamondLog diamondLog = new DiamondLog();
        diamondLog.setBalance(diamondBalance);
        diamondLog.setChanges(diamond);
        diamondLog.setCreateTime(DateUtil.getCurUnixTimeStampInt());
        diamondLog.setLogId(diamondRechargeLogId);
        diamondLog.setUid(login_uid);
        diamondLogService.save(diamondLog);

        //增加用户钻 钻石服务器计算得出
        HashMap map = new HashMap();
        map.put("change", money.multiply(new BigDecimal(10)));
        map.put("uid", login_uid);
        if(!type.equals(Constants.PAY_TYPE_IAP_SANDBOX) && !type.equals(Constants.PAY_TYPE_MANUAL)) {
            map.put("type", "recharge");
        }
        if (user.getIsPrivate()==0){
            BigDecimal totalMoney=diamondRechargeLogService.getTotalMoney( user.getId());
            int total=totalMoney.intValue()+money.intValue();
            System.out.println("-----totalmoney---"+total);
            if (total>= Constants.BASEMNOEY){
                map.put("isPrivate", 1);
            }
        }
        diamondRechargeLogService.setInc(map);

        return null;
    }


    @PostMapping("/recharge")
    public Result recharge(Long login_uid, String money, Integer type) throws Exception{
        switch (type){
            case 0:
                System.out.println("PAY_TYPE_MANUAL");
                break;
            case 1:
                System.out.println("PAY_TYPE_IAP");
                break;
            case 2:
                System.out.println("PAY_TYPE_IAP_SANDBOX");
                break;
            case 3:
                System.out.println("PAY_TYPE_ALIPAY");
                String result = createData(login_uid,money,type);
                if(null!=result)
                    return ResultGenerator.genSuccessResult(result);
                break;
            case 4:
                System.out.println("PAY_TYPE_WECHAT");
                break;
            case 5:
                System.out.println("PAY_TYPE_UNIONPAY");
                break;
            default :
                System.out.println("default");
                break;
        }
        return null;
    }


    private String createData(Long login_uid,String fee,Integer type){
        try {
            Date date = new Date();
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String time = formatter.format(date);

            //自定义20位订单ID
            String out_trade_no = DateUtil.getCurrentTime() + DateUtil.getRandom(3);

            Map<String,String> map = new HashMap<>();
            map.put("app_id", AlipayConfig.app_id);
            map.put("method", "alipay.trade.app.pay");
            map.put("charset", AlipayConfig.input_charset);
            map.put("sign_type", AlipayConfig.sign_type);
            map.put("timestamp",time);
            map.put("version", "1.0");
            map.put("notify_url", AlipayConfig.notify_url);

            Map<String,String> map_bc = new HashMap<>();
            map_bc.put("body", login_uid + "-" + type);
            map_bc.put("subject","充值");

            map_bc.put("out_trade_no", out_trade_no);
            map_bc.put("timeout_express", "30m");
            map_bc.put("total_amount", fee);
            map_bc.put("seller_id", AlipayConfig.partner);
            map_bc.put("product_code", "QUICK_MSECURITY_PAY");

            String biz_content = JSON.toJSONString(map_bc);

            map.put("biz_content", biz_content);
            String sign = buildRequestMysign(map);

            Map<String,String> map_z = new HashMap<>();
            map_z.put("app_id", AlipayConfig.app_id);
            map_z.put("method", "alipay.trade.app.pay");
            map_z.put("charset", AlipayConfig.input_charset);
            map_z.put("sign_type", AlipayConfig.sign_type);
            map_z.put("timestamp", URLEncoder.encode(time,"utf-8"));
            map_z.put("version", "1.0");
            map_z.put("notify_url", URLEncoder.encode(AlipayConfig.notify_url,"utf-8"));
            map_z.put("biz_content", URLEncoder.encode(biz_content,"utf-8"));

            String str = AlipayCore.createLinkString(map_z);
            sign = URLEncoder.encode(sign,"utf-8");
            String result = str + "&sign="+sign;
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String buildRequestMysign(Map<String, String> sPara) {
        String prestr = AlipayCore.createLinkString(sPara);
        String mysign = "";
        if(AlipayConfig.sign_type.equals("RSA") ){
            mysign = RSA.sign(prestr, AlipayConfig.private_key, AlipayConfig.input_charset);
        }
        return mysign;
    }


    @RequestMapping("/zfb_ybtz")
    public void zfb_ybtz(HttpServletRequest request, HttpServletResponse resp) {
        String meg = "fail";
        Map<String,String> params = new HashMap<String,String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        try {
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8");
            if(AlipayNotify.verify(params)){
                if(trade_status.equals("TRADE_FINISHED")){
                } else if (trade_status.equals("TRADE_SUCCESS")){
                    String body = new String(request.getParameter("body").getBytes("ISO-8859-1"),"UTF-8");
                    String transactionId = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8");
                    String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8");
                    BigDecimal money = new BigDecimal(total_amount);
                    BigDecimal diamond = money.multiply(new BigDecimal("10"));
                    String createTime = new String(request.getParameter("gmt_create").getBytes("ISO-8859-1"),"UTF-8");
                    Integer timeStemp = DateUtil.date2TimeStamp(createTime);
                    String[] str = body.split("-");
                    Long login_uid = Long.parseLong(str[0]);
                    Integer payType = Integer.parseInt(str[1]);

                    String payResult = doPay(login_uid, payType, transactionId, money, diamond, timeStemp, params.toString());
                    if (payResult == null)
                        meg = "success";
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            resp.setCharacterEncoding("utf-8");
            resp.getWriter().write(meg);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    @PostMapping("/recharge_log")
    public Result recharge_log(Long login_uid, Integer page, Integer page_size) {
        PageUtil.startPage(page, page_size);
        Map<String, Object> map = new HashMap();
        map.put("uid", login_uid);
        List<HashMap> diamondRechargeLogList = diamondRechargeLogService.getRechargeLogList(map);
        HashMap diamondRechargeLogListHashMap = PageUtil.getPageInfoHashMap(new PageInfo(diamondRechargeLogList));

        return ResultGenerator.genSuccessResult(diamondRechargeLogListHashMap);
    }


}
